/**
 * Created by Weizehua on 2017/1/17.
 */
import {Handle, HandlerClass, ParamType, Validators, RequireHandler} from "../Core/Dispatcher/Dispatcher";
import {Injector, Injectable} from "ts.di";
import {tr} from "../Core/Localization/Translator";
import {HandlerResponse, RequestUserInfo} from "../Core/Dispatcher/Types";
import {UserService} from "./UserService";
import {CaptchaService} from "../Captcha/CaptchaService";
import {Hash} from "../Core/Hash/Hash";
import {Connection} from "typeorm";
import {UserInfo} from "../UserInfo/UserInfo";

@HandlerClass()
@Injectable()
export class UserHandler {
    constructor(protected typeorm: Connection,
                private service: UserService,
                private hasher: Hash,
                private captchaService: CaptchaService) {
    }

    //noinspection JSUnusedGlobalSymbols
    @Handle('/login')
    @ParamType({
        username: String,
        password: String
    })
    async loginHandler(param: any): Promise<HandlerResponse> {
        let user = await this.service.login(param.username, param.password);
        if (!user) {
            return tr(`username or password error`)
        }
        let info = await this.typeorm.entityManager.findOne(UserInfo, {user: user.id});
        user.nickname = info.nickname;
        user.headUrl = info.headUrl;
        return {
            success: true,
            userInfo: user
        }
    }

    // @Handle('/register/phone/getCaptcha')
    @ParamType({
        phone: String,
    })
    @Validators({
        phone: [
            UserService.isPhoneString,
            async phone => await Injector.get(UserService).isPhoneRegistered(phone) ? tr`phone number : ${phone} already registered!` : true,
        ]
    })
    async registerWithPhoneGetCaptchaHandler(param: any): Promise<any> {
        let info = await this.captchaService.sendCaptcha(param.phone);
        return info.success ?
            {success: true, captchaInfo: info} : info.reason;
    }

    @Handle('/register/phone')
    @ParamType({
        phone: String,
        captcha: String,
        password: String,
        captchaInfo: {
            // captchaDigest: String,
            signature: String,
            expiredDate: Date
        },
    })
    @Validators({
        phone: [
            UserService.isPhoneString,
            async phone => await Injector.get(UserService).isPhoneRegistered(phone) ? tr`phone number : ${phone} already registered!` : true,
        ]
    })
    async registerWithPhoneHandler(param: any): Promise<any> {
        if (new Date() > param.captchaInfo.expiredDate)
            return tr`验证码已过期，该验证码在${param.captchaInfo.expiredDate.toDateString()}之前有效`;
        if (!await this.captchaService.validateCaptcha(param.phone, param.captcha, param.captchaInfo))
            return tr(`验证码校验失败，你所提供的验证码为：${param.captcha}`);

        // register
        return await this.service.registerWithPhone(param.phone, param.password);
    }

    @Handle('/register/phone/isRegistered')
    @ParamType({
        phone: String,
    })
    @Validators({
        phone: [UserService.isPhoneString]
    })
    async isPhoneRegisteredHandler(param: any): Promise<any> {
        return {success: true, status: await this.service.isPhoneRegistered(param.phone)}
    }

    @RequireHandler()
    async isLogged(userInfo: RequestUserInfo) {
        if (!userInfo || !await this.hasher.verifyUser(
                userInfo.id,
                userInfo.permissions,
                userInfo.expiredDate, userInfo.signature)) {
            return tr("用户认证失败，签名不正确");
        }

        return true;
    }

    @RequireHandler()
    async isAdmin(userInfo: RequestUserInfo) {
        if (!userInfo || !await this.hasher.verifyUser(
                userInfo.id,
                userInfo.permissions,
                userInfo.expiredDate, userInfo.signature)) {
            return tr("用户认证失败，签名不正确");
        }
        if (!userInfo.permissions.admin)
            return tr("用户认证失败，你不是管理员");

        return true;
    }
}

export let isLogged = UserHandler.prototype.isLogged;
export let isAdmin = UserHandler.prototype.isAdmin;
